/**
 * 合并数据
 * @param {*} defaultClass
 * @param {*} partialOptions
 * @returns
 */
export function mergeOptions(defaultClass, partialOptions) {
  const options = {};
  for (const key in defaultClass) {
    options[key] =
      key in partialOptions ? partialOptions[key] : defaultClass[key];
  }
  return options;
}

/**
 * 规范路由属性
 * @param record
 */
function normalizeRecordProps(record) {
  const propsObject = {};
  const props = record.props || false; // 取出 router 路由 props 属性
  if ("component" in record) {
    propsObject.default = props;
  } else {
    for (const name in record.components) {
      propsObject[name] = typeof props === "boolean" ? props : props[name];
    }
  }
  return propsObject;
}

/**
 * 规范格式化路由
 * @param record
 * @returns
 */
export function normalizeRouteRecord(record) {
  // 拍平后路由信息
  return {
    path: record.path,
    redirect: record.redirect,
    name: record.name,
    meta: record.meta || {},
    aliasOf: undefined,
    beforeEnter: record.beforeEnter,
    props: normalizeRecordProps(record),
    children: record.children || [], // 孩子
    instances: {},
    leaveGuards: new Set(),
    updateGuards: new Set(),
    enterCallbacks: {},
    components:
      "components" in record
        ? record.components || null
        : record.component && { default: record.component },
  };
}

/**
 * 创建路由匹配器构建路由父子关系
 * @param {*} record
 * @param {*} parent
 * @returns
 */
export function createRouteRecordMatcher(record, parent) {
  // 解析路径(因为路径可能为正则)
  // const parser = tokensToParser(tokenizePath(record.path), options);
  const parser = {};
  const matcher = Object.assign({}, parser, {
    record: { path: record.path }, // record 中存放着一些匹配结果
    parent,
    children: [],
    alias: [],
  });
  // 判断是否有父路由存在则孩子中添加当前子路由
  if (parent) {
    parent.children.push(matcher); // 给父路由孩子属性添加自己
  }
  return matcher;
}

/**
 * 将路由数组扁平化
 * @internal
 * @param routes
 * @param globalOptions
 */
export function createRouterMatcher(routes, globalOptions) {
  const matchers = []; // 存放拍平后路由
  const matcherMap = new Map();
  // 合并选项用于路径匹配
  globalOptions = mergeOptions(
    { strict: false, end: true, sensitive: false },
    globalOptions
  );
  console.log(matchers, globalOptions);

  function getRecordMatcher(name) {
    return matcherMap.get(name);
  }

  /**
   * 动态添加路由
   * @param {*} record 当前路由
   * @param {*} parent 父级路由
   * @param {*} originalRecord 原始路由
   * @returns
   */
  function addRoute(record, parent) {
    const mainNormalizedRecord = normalizeRouteRecord(record); // 规范当前路由记录
    const normalizedRecords = [mainNormalizedRecord]; // 转为数组
    let matcher;
    // 遍历当前路由配置选项
    for (const normalizedRecord of normalizedRecords) {
      const { path } = normalizedRecord;
      // 有父路由时当前路由路径则是拼接父级基础而成
      if (parent && path[0] !== "/") {
        const parentPath = parent.record.path; // 父路由路径
        const connectingSlash =
          parentPath[parentPath.length - 1] === "/" ? "" : "/";
        normalizedRecord.path =
          parent.record.path + (path && connectingSlash + path); // 拼接父路径成为当前路径
      }
      matcher = createRouteRecordMatcher(normalizedRecord, parent);
      // 存在子路由时进行递归操作
      if (mainNormalizedRecord.children) {
        const children = mainNormalizedRecord.children;
        for (let i = 0; i < children.length; i++) {
          addRoute(children[i], matcher); // 深度递归路由
        }
      }
      // if (
      //   (matcher.record.components &&
      //     Object.keys(matcher.record.components).length) ||
      //   matcher.record.name ||
      //   matcher.record.redirect
      // ) {
      insertMatcher(matcher); // 将路由匹配记录存放队列中
      // }
    }
    return matcher;
  }

  // function removeRoute(matcherRef) {
  //   if (isRouteName(matcherRef)) {
  //     const matcher = matcherMap.get(matcherRef)
  //     if (matcher) {
  //       matcherMap.delete(matcherRef)
  //       matchers.splice(matchers.indexOf(matcher), 1)
  //       matcher.children.forEach(removeRoute)
  //       matcher.alias.forEach(removeRoute)
  //     }
  //   } else {
  //     const index = matchers.indexOf(matcherRef)
  //     if (index > -1) {
  //       matchers.splice(index, 1)
  //       if (matcherRef.record.name) matcherMap.delete(matcherRef.record.name)
  //       matcherRef.children.forEach(removeRoute)
  //       matcherRef.alias.forEach(removeRoute)
  //     }
  //   }
  // }

  // function getRoutes() {
  //   return matchers
  // }

  /**
   * 按位置插入路由匹配结果
   * @param {*} matcher
   */
  function insertMatcher(matcher) {
    matchers.push(matcher);
    if (matcher.record.name) {
      matcherMap.set(matcher.record.name, matcher); // 记录当前路由匹配
    }
  }

  // function resolve(
  //   location: Readonly<MatcherLocationRaw>,
  //   currentLocation: Readonly<MatcherLocation>
  // ): MatcherLocation {
  //   let matcher: RouteRecordMatcher | undefined
  //   let params: PathParams = {}
  //   let path: MatcherLocation['path']
  //   let name: MatcherLocation['name']

  //   if ('name' in location && location.name) {
  //     matcher = matcherMap.get(location.name)

  //     if (!matcher)
  //       throw createRouterError<MatcherError>(ErrorTypes.MATCHER_NOT_FOUND, {
  //         location,
  //       })

  //     // warn if the user is passing invalid params so they can debug it better when they get removed
  //     if (__DEV__) {
  //       const invalidParams: string[] = Object.keys(
  //         location.params || {}
  //       ).filter(paramName => !matcher!.keys.find(k => k.name === paramName))

  //       if (invalidParams.length) {
  //         warn(
  //           `Discarded invalid param(s) "${invalidParams.join(
  //             '", "'
  //           )}" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`
  //         )
  //       }
  //     }

  //     name = matcher.record.name
  //     params = assign(
  //       // paramsFromLocation is a new object
  //       paramsFromLocation(
  //         currentLocation.params,
  //         // only keep params that exist in the resolved location
  //         // TODO: only keep optional params coming from a parent record
  //         matcher.keys.filter(k => !k.optional).map(k => k.name)
  //       ),
  //       // discard any existing params in the current location that do not exist here
  //       // #1497 this ensures better active/exact matching
  //       location.params &&
  //         paramsFromLocation(
  //           location.params,
  //           matcher.keys.map(k => k.name)
  //         )
  //     )
  //     // throws if cannot be stringified
  //     path = matcher.stringify(params)
  //   } else if ('path' in location) {
  //     // no need to resolve the path with the matcher as it was provided
  //     // this also allows the user to control the encoding
  //     path = location.path

  //     if (__DEV__ && !path.startsWith('/')) {
  //       warn(
  //         `The Matcher cannot resolve relative paths but received "${path}". Unless you directly called \`matcher.resolve("${path}")\`, this is probably a bug in vue-router. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/router.`
  //       )
  //     }

  //     matcher = matchers.find(m => m.re.test(path))
  //     // matcher should have a value after the loop

  //     if (matcher) {
  //       // we know the matcher works because we tested the regexp
  //       params = matcher.parse(path)!
  //       name = matcher.record.name
  //     }
  //     // location is a relative path
  //   } else {
  //     // match by name or path of current route
  //     matcher = currentLocation.name
  //       ? matcherMap.get(currentLocation.name)
  //       : matchers.find(m => m.re.test(currentLocation.path))
  //     if (!matcher)
  //       throw createRouterError<MatcherError>(ErrorTypes.MATCHER_NOT_FOUND, {
  //         location,
  //         currentLocation,
  //       })
  //     name = matcher.record.name
  //     // since we are navigating to the same location, we don't need to pick the
  //     // params like when `name` is provided
  //     params = assign({}, currentLocation.params, location.params)
  //     path = matcher.stringify(params)
  //   }

  //   const matched: MatcherLocation['matched'] = []
  //   let parentMatcher: RouteRecordMatcher | undefined = matcher
  //   while (parentMatcher) {
  //     // reversed order so parents are at the beginning

  //     matched.unshift(parentMatcher.record)
  //     parentMatcher = parentMatcher.parent
  //   }

  //   return {
  //     name,
  //     path,
  //     params,
  //     matched,
  //     meta: mergeMetaFields(matched),
  //   }
  // }

  // 遍历用户路由配置得到拍平后具有规范路由信息

  routes.forEach((route) => addRoute(route));
  console.log(matchers);
  return { addRoute, getRecordMatcher };
}
